<template>
    <div>vue2实验地</div>
    <div>{{ propDefaultValue }}</div>
    <!-- ******************************************************************************** -->
    <!-- computed -->
    <div>{{ computedNum }}</div>
    <div>{{ double1 }}</div>
    <div>{{ double2 }}</div>
    <input type="text" v-model="double2">
    <button @click="computedGET">computedGET</button>
    <br />
    <button @click="computedSET">computedSET</button>
    <br />
    <!-- ******************************************************************************** -->
    <!-- watch -->
    <button @click="watchInfoEvent">watchInfoEvent</button>
    <!-- ******************************************************************************** -->
    <!-- 动态css属性 -->
    <p v-bind:class="{ black: isBlack, yellow: isYellow }">使用class</p>
    <p :class="[black, yellow]">使用class(数组)</p>
    <p :style="styleData">使用class(数组)</p>
    <!-- ******************************************************************************** -->
    <!-- v-for -->
    <ul>
        <li v-for="(item, index) in listArr" :key="item.id">
            {{ `数组循环：${item.title}--${index}` }}
        </li>
    </ul>
    <ul>
        <!-- 对象也可以循环，v-for与v-if因避免在同一个标签使用，v-for的优先级比v-if高，所以每一遍循环都会触发v-if -->
        <!-- v-for为什么需要key -->
        <!-- https://blog.csdn.net/weixin_52998620/article/details/122970118 -->
        <li v-if="forflag" v-for="(val, key, index) in listObj" :key='key'>
            {{ `对象循环：${val}--${key}--${index}` }}
        </li>
    </ul>
    <!-- ******************************************************************************** -->
    <!-- v-model -->
    <!--  trim修饰符：将用户输入的文本信息中开头的空格，结尾的空格都删除-->
    <input type="text" v-model.trim="VmodelName">
    <!--  lazy修饰符：使得用户在输入数据之后，当数据失去焦点或点击回车时，才会进行数据的更新-->
    <input type="text" v-model.lazy="VmodelName">
    <!-- 当用户在input中输入数字时，浏览器会默认将输入的数字转化为string类型，使用number修饰符来将输入的数字转为number类型 -->
    <input type="text" v-model.number="VmodelAge">
    <div>{{ `${VmodelName}---${VmodelAge}` }}</div>
    <!-- ******************************************************************************** -->
    <!-- 父子组件生命周期顺序 -->
    <!-- 当父组件执行完beforemount后,就执行子组件，子组件执行完mounted后，再执行父组件的mounted -->
    <!-- <vue2son></vue2son> -->
    <vue2son v-if="showVue2son"></vue2son>
    <!-- props双向绑定 -->
    <div>{{`v2的.sync修饰符对prop进行双向绑定${sxbdState}`}}</div>
    <!-- .sync修饰符v3废弃，v3使用v-model对prop进行双向绑定 -->
    <!-- <component :is="componentTYPE" :sxbdState.sync="sxbdState"/> -->
    <component :is="componentTYPE" v-model:sxbdState="sxbdState"  :sxtc='"属性透传"'/>
    <button @click="componentEvent">动态组件+异步组件</button>
    <!-- ******************************************************************************** -->
    <!-- 自定义v-model 没懂-->
    <!-- <input type="text" v-model="modelName"> -->
    <p>{{modelName}}</p>
    <!-- <CustomVModel v-model="modelName"> -->
    <!-- ******************************************************************************** -->
    <ul ref="ul1">
        <li v-for="(item,index) in nextTickList" :key="index">{{item}}</li>
    </ul>
    <button @click="nextTickEvent">nextTick</button>
    <!-- ******************************************************************************** -->
    <!-- ******************************************************************************** -->
    <!-- ******************************************************************************** -->
    <!-- ******************************************************************************** -->
    <!-- ******************************************************************************** -->

</template>
    
<script lang="ts">
import { defineComponent, nextTick } from 'vue'
import vue2son from './components/vue2Son.vue'
import CustomVModel from './components/CustomVModel.vue'
export default defineComponent({
    //设置父组件传递的属性值类型，和默认值
    //props对象形式写法
    props: {
        propDefaultValue1:[String,Number],//对象形式简写
        propDefaultValue: {
            type: [String,Number],//联合类型可以是string或number
            required:true,//必有
            default() {//默认值
                return 'prop值'
            }
        }
    },
    //props数组形式写法
    // props:['propDefaultValue'],
    components: {
        vue2son
        /**
         * 异步组件
         * 当组件过大，且不会立马使用
         */
        // vue2son:()=>import('./components/vue2Son.vue')
        ,CustomVModel
    },
    data() {
        return {
            isBlack: true,
            isYellow: true,
            black: 'black',
            yellow: 'yellow',
            styleData: {
                color: 'red'
            },

            computedNum: 20,

            watchName: '袁六六',
            watchInfo: {
                city: '广德'
            },

            listArr: [
                { id: 'a', title: '标题1' },
                { id: 'b', title: '标题2' },
                { id: 'c', title: '标题' }
            ],
            listObj: {
                'a': { title: '标题1' },
                'b': { title: '标题2' },
                'c': { title: '标题' }
            },
            forflag: true,

            VmodelName: '袁六六',
            VmodelAge: 6,

            modelName:'自定义model',

            nextTickList:['a'],

            componentTYPE:'vue2son',

            showVue2son:false,

            sxbdState:'7777',
        }
    },
    computed: {
        //computed有缓存，绑定的值不变不会重新计算（像例子中的double1和double2的get方法）
        //用计算属性作为双向数据绑定，一定要有set
        double1(): number {//computed默认是get方法
            return this.computedNum * 2
        },
        double2: {
            get(): number {
                console.log('我是get');
                return this.computedNum * 2
            },
            set(val: number) {
                console.log('我是set');
                this.computedNum = val / 2
            }
        }
    },
    watch: {
        //普通浅度监听（只能监听到第一层watchInfo,第二层city以后的就不行了）
        watchName(oldVal, val) {
            //值类型可以正常拿到oldval,val
            console.log('watch name', oldVal, val);
        },
        watchInfo: {
            handler(oldVal, val) {
                //引用类型，拿不到oldval,因为指针相同，此时已经指向新的val了
                //引用类型直接赋值或者修改里面的值，都是指针赋值(改变指向)
                console.log('watch info', oldVal, val);

            },
            deep: true //深度监听
        }
    },
    methods: {
        //触发computed的get方法(当绑定的data里的值发生了改变触发get)
        computedGET() {
            this.computedNum = this.computedNum + 1
        },
        //触发computed的set方法（当计算属性发生了改变会触发set）
        computedSET() {
            this.double2 = 100
        },
        //修改watch里监听的引用类型的值
        watchInfoEvent() {
            this.watchInfo.city = '上海'
        },
        /**
         * nextTick
         * 1.vue是异步渲染，data改变后，DOM不会立刻渲染
         * 2.$nextTick会在DOM渲染完之后被触发，以获取最新DOM
         * 3.页面渲染会将data的修改做整合，多次data
         */
        nextTickEvent(){

            this.nextTickList.push(`${Date.now()}`)
            this.nextTickList.push(`${Date.now()}`)
            this.nextTickList.push(`${Date.now()}`)  
            this.nextTickList.push(`${Date.now()}`)  
            //ulElem类型报错,只能拿到push2个的长度值什么原理？？？
            // const ulElem = this.$refs.ul1//获取名字叫ul1的dom元素
            // console.log(ulElem.children.length)// children：非标准属性，它返回指定元素的子元素集合
            this.$nextTick(()=>{
                const ulElem = <Element>this.$refs.ul1//获取名字叫ul1的dom元素
                console.log(ulElem.children.length)
            })

        },
        /**
         * 动态组件（如：新闻详情页，多组件使用顺序和类型不定）
         * 需要根据数据，动态渲染的场景，即组件类型不确定
         * 
         */
        componentEvent(){
            
            this.componentTYPE = 'vue2son'
            this.showVue2son = true
        }
    },
    beforeCreate() {
        console.log("父组件生命周期beforeCreate");
    },
    created() {
        console.log("父组件生命周期created");
        /**
         * 单向数据流
         * 所有的 props 都遵循着单向绑定原则,props上的属性是只读的无法修改
         * https://cn.vuejs.org/guide/components/props.html#one-way-data-flow
         */
        // this.propDefaultValue = '改变props里的值'
    },
    // beforemount() {
    //     //为什么打印出来
    //     console.log("父组件生命周期beforemount");
    // },
    // mounted() {
    //     console.log("父组件生命周期mounted");
    // },
    // beforeUpdata() {
    //     console.log("父组件生命周期beforeUpdata");
    // },
    // updated() {
    //     console.log("父组件生命周期updated");
    // },
    // beforeDestroy() {
    //     console.log("父组件生命周期beforeDestroy");
    // },
    // destroyed() {
    //     console.log("父组件生命周期destroyed");
    // }
})
</script>
<style scoped>
.black {
    color: black;
}

.yellow {
    background-color: yellow;
}
</style>